In this notebook we classify all symmetry-exceptional slopes of the asymmetric L-space knots in the SnapPy census. For that we compute (as explained in the paper) for any knot the slopes with length less than 10.2 and compute the symmetry groups of the corresponding fillings.

We start with the 9 asymmetric L-space knots.

In [1]:
D=['t12533','t12681','o9_38928','o9_39162','o9_40363','o9_40487','o9_40504','o9_40582','o9_42675']

The corresponding code is as follows.

In [2]:
import math
import pandas
import time
import snappy

# We load Dunfield's list from of all exceptional surgeries along the SnapPy CensusKnots.
exceptional_filllings = pandas.read_csv("exceptional_fillings.csv") 

def better_symmetry_group(M,index=10,time_cut_off=False,max_time=60):
    '''
    This function computes the verified symmetry group of the input manifold. 
    If SnapPy cannot rigorously the symmetry group it returns 'unclear'.
    The higher the index the harder SnapPy searches. A time limit is possible.
    '''
    start_time = time.time()
    w=False
    randomizeCount=0
    try:
        S=M.symmetry_group()
        w=S.is_full_group()
    except ValueError:
        pass
    except RuntimeError:
        pass
    except snappy.SnapPeaFatalError:
        pass
    if w==False:
        while randomizeCount<index and w==False:
            M.randomize()
            randomizeCount=randomizeCount+1
            try:
                S=M.symmetry_group()
                w=S.is_full_group()
            except ValueError:
                pass
            except RuntimeError:
                pass
            except snappy.SnapPeaFatalError:
                pass
            if time_cut_off==True and (time.time() - start_time) >max_time:
                return 'unclear'
    if w==True:
        return S
    if w==False:
        return 'unclear'
    
def Bound(systole):
    '''
    Takes as input a systole and computes the bound from FPS19.
    '''
    B= math.sqrt(2*math.pi/systole +58)
    if 10.1>B:
        return 10.11
    else:
        return B+0.01

def better_systole(M,index):
    '''
    Computes the systole of a manifold. 
    It returns 'unclear' if SnapPy cannot compute the systole.
    '''
    w=False
    randomizeCount=0
    try:
        systole=M.dual_curves()[0].complete_length.real() 
        w=True
    except ValueError:
        pass
    except RuntimeError:
        pass
    except SnapPeaFatalError:
        pass
    except IndexError:
        pass
    if w==False:
        while randomizeCount<index and w==False:
            M.randomize()
            randomizeCount=randomizeCount+1
            try:
                systole=M.length_spectrum()[0].length.real() 
                w=True
            except ValueError:
                pass
            except RuntimeError:
                pass
            except snappy.SnapPeaFatalError:
                pass
            except IndexError:
                pass
    if w==True:
        return systole
    if w==False:
        return 'unclear' 

def exceptional_slopes(knot):
    """
    Takes a knot from the SnapPy census and reads off from Dunfield's list its exceptional surgeries.
    """
    exceptional_slopes_strings=exceptional_filllings.loc[(exceptional_filllings['cusped'] == knot)]['slope'].tolist()
    exceptional_slopes=[]
    for string in exceptional_slopes_strings:
        string_without_brackets=string[1:-1]
        exceptional_slopes.append(tuple(map(int, string_without_brackets.split(', '))))
    return exceptional_slopes

def compute_exceptional_symmetry_slopes(knot,index=10,time_cut=False,max_time_cut_off=120):
    '''
    Returns the exceptional symmetry slopes, the exceptional slopes and and the slopes where SnapPy could not compute its symmetry groups.
    '''
    start_time = time.time()
    K=snappy.Manifold(knot)
    systole=better_systole(K,index)
    if systole=='unclear':
        return [K.name(),'cannot compute systole']
    B=Bound(systole)
    exc_slopes=exceptional_slopes(knot)
    small_slopes=[s for s in K.short_slopes(length=B*math.sqrt(K.cusp_areas()[0]))[0] if s not in exc_slopes] # The small hyperbolic slopes.
    exceptional_symmetry_slopes=[]
    smaller_groups=[]
    unclear_slopes=[]
    S=better_symmetry_group(K,index)
    if S=='unclear':
        return [K.name(),'cannot compute symmetry group']
    for s in small_slopes:
        K.dehn_fill(s)
        if time_cut==True and (time.time() - start_time) >max_time_cut_off:
            unclear_slopes.append(s)
        else:
            T=better_symmetry_group(K,index,time_cut_off=time_cut,max_time=max_time_cut_off/10)
            if T=='unclear':
                unclear_slopes.append(s)
            else:
                if T.order()>S.order():
                    exceptional_symmetry_slopes.append([s,T])
                if T.order()<S.order():
                    smaller_groups.append([s,T])
    return [K.name(),S,len(small_slopes),exc_slopes,exceptional_symmetry_slopes,smaller_groups,unclear_slopes]
In [3]:
EXSYM=[]  

start_time = time.time()
for K in D: 
    EXSYM.append(compute_exceptional_symmetry_slopes(K,index=1000))
print("--- Time taken: %s minutes ---" % ((time.time() - start_time)/60))
--- Time taken: 5.907751727104187 minutes ---

We get the list of exceptional symmetry slopes as claimed in the paper.

In [4]:
EXSYM
Out[4]:
[['t12533',
  0,
  97,
  [(1, 0)],
  [[(-3, 1), Z/2],
   [(-2, 1), Z/2],
   [(-1, 1), Z/2],
   [(0, 1), Z/2],
   [(1, 1), Z/2],
   [(-1, 2), Z/2]],
  [],
  []],
 ['t12681',
  0,
  96,
  [(1, 0), (0, 1)],
  [[(-1, 1), Z/2],
   [(1, 1), Z/2 + Z/2],
   [(-1, 2), Z/2],
   [(-2, 3), Z/2],
   [(-1, 3), Z/2]],
  [],
  []],
 ['o9_38928',
  0,
  100,
  [(1, 0)],
  [[(-2, 1), Z/2],
   [(-1, 1), Z/2],
   [(0, 1), Z/2],
   [(1, 1), Z/2],
   [(2, 1), Z/2 + Z/2]],
  [],
  []],
 ['o9_39162',
  0,
  95,
  [(1, 0), (0, 1)],
  [[(-1, 1), Z/2], [(1, 1), Z/2], [(2, 1), Z/2], [(1, 2), Z/2], [(1, 4), Z/2]],
  [],
  []],
 ['o9_40363',
  0,
  98,
  [(1, 0), (0, 1)],
  [[(-1, 1), Z/2],
   [(1, 1), Z/2 + Z/2],
   [(-1, 2), Z/2],
   [(-1, 3), Z/2],
   [(-3, 4), Z/2]],
  [],
  []],
 ['o9_40487',
  0,
  100,
  [(1, 0)],
  [[(-2, 1), Z/2],
   [(-1, 1), Z/2],
   [(0, 1), Z/2],
   [(1, 1), Z/2],
   [(2, 1), Z/2],
   [(3, 1), Z/2],
   [(1, 2), Z/2]],
  [],
  []],
 ['o9_40504',
  0,
  99,
  [(1, 0)],
  [[(-2, 1), Z/2],
   [(-1, 1), Z/2],
   [(0, 1), Z/2],
   [(1, 1), Z/2],
   [(2, 1), Z/2 + Z/2]],
  [],
  []],
 ['o9_40582',
  0,
  97,
  [(1, 0)],
  [[(-1, 1), Z/2],
   [(0, 1), Z/2],
   [(1, 1), Z/2],
   [(2, 1), Z/2],
   [(4, 1), Z/2],
   [(1, 2), Z/2]],
  [],
  []],
 ['o9_42675',
  0,
  99,
  [(1, 0)],
  [[(-2, 1), Z/2 + Z/2],
   [(-1, 1), Z/2],
   [(0, 1), Z/2],
   [(1, 1), Z/2],
   [(2, 1), Z/2]],
  [],
  []]]

Since for any knot the last two sets are empty it follows that our results are complete and that we have actually found any symmetric slope of the knots in D.